<script lang="ts" setup>
import { StorageConst } from '@/constant';
import { DefaultApiUrls, type LoginByAccountVo } from '@/openapi-generator';
import { initRouters } from '@/router';
import storage from '@/storage';
import { loadMenuList } from '@/stores/menu';
import { message, type FormInstance } from 'ant-design-vue';
import type { Rule } from 'ant-design-vue/es/form';
import { reactive, ref } from 'vue';
import { useRouter } from 'vue-router';

const router = useRouter();
const formRef = ref<FormInstance>();
const verifyCodeUrl = ref<string>(DefaultApiUrls.verifyCodeGetImageCode);
const state = reactive({
  loginLoading: false
});
// 表单
const form = reactive({
  username: "",
  password: "",
  verifyCode: "",
  remember: true
});
const token = ref<string>("");

// 登录校验
const verifyLogin = async (_rule: Rule, value: string) => {
  let res;
  let body: LoginByAccountVo = {
    account: form.username,
    password: form.password,
    verifyCode: form.verifyCode
  }

  try {
    state.loginLoading = true;
    res = await $adminApi.authenticationLoginByAccount(body, { hideToast: true });
  } catch (error: any) {
    refreshVerifyCode();
    return Promise.reject(error && error.message ? error.message : "登录失败");
  } finally {
    state.loginLoading = false;
  }

  token.value = res.data;
  return Promise.resolve();
}

// 登录成功
const onLoginSuccess = async () => {
  // TODO 获取用户信息
  // 写缓存
  storage.setItem(StorageConst.Token, token.value);
  // 获取菜单信息
  try {
    await initMenu();
  } catch (error) {
    message.error("初始化菜单失败.");
    return
  }
  router.replace("/");
  message.success("登录成功");
}

// 校验
const rules: any = {
  username: [
    { required: true, trigger: 'blur', message: "请输入账号" }
  ],
  password: [
    { required: true, trigger: 'blur', message: "请输入密码" }
  ],
  verifyCode: [
    { required: true, trigger: 'blur', message: "请输入验证码" },
    { validator: verifyLogin, trigger: 'none' }
  ]
};

// 刷新验证码
const refreshVerifyCode = () => {
  verifyCodeUrl.value = DefaultApiUrls.verifyCodeGetImageCode + '?t=' + new Date().getTime();
}

// 初始化菜单
const initMenu = async () => {
  let data;

  try {
    data = await loadMenuList();
  } catch (error) {
    return
  }
  window._menuListCache = data.records;
  initRouters();
}
</script>

<template>
  <!-- 登录页 -->
  <section class="container">
    <a-card class="login-card">
      <div class="card-body">
        <h2>爱购物商城系统</h2>
        <div class="form-box">
          <a-form ref="formRef" :model="form" :rules="rules" autocomplete="off" @finish="onLoginSuccess">
            <a-form-item name="username">
              <a-input v-model:value="form.username" placeholder="请输入账号">
                <template #prefix>
                  <user-outlined type="user" />
                </template>
              </a-input>
            </a-form-item>

            <a-form-item name="password">
              <a-input-password v-model:value="form.password" placeholder="请输入密码">
                <template #prefix>
                  <lock-outlined />
                </template>
              </a-input-password>
            </a-form-item>

            <a-form-item name="verifyCode" validate-first>
              <a-row :gutter="20">
                <a-col :span="16">
                  <a-input :maxlength="4" v-model:value="form.verifyCode" placeholder="请输入验证码">
                    <template #prefix>
                      <safety-certificate-outlined />
                    </template>
                  </a-input>
                </a-col>
                <a-col :span="8">
                  <span class="verify-box">
                    <img @click="refreshVerifyCode" :src="verifyCodeUrl">
                  </span>
                </a-col>
              </a-row>
            </a-form-item>

            <a-form-item name="remember">
              <a-row justify="space-between">
                <a-col>
                  <a-checkbox v-model:checked="form.remember">在这台设备保持登录</a-checkbox>
                </a-col>
                <a-col>
                  <a-button type="link">忘记密码?</a-button>
                </a-col>
              </a-row>
            </a-form-item>

            <a-form-item>
              <a-button block type="primary" html-type="submit" :loading="state.loginLoading">登录</a-button>
            </a-form-item>

            <a-divider>其他方式登录</a-divider>

            <div class="other-mode">
              <span>
                <wechat-outlined />
              </span>
              <span>
                <qq-outlined />
              </span>
            </div>

            <!-- 一般不开放账号注册 由管理员添加 -->
            <div class="register-box" v-if="false">
              <a-button type="link">注册账号</a-button>
            </div>
          </a-form>
        </div>
      </div>
    </a-card>
  </section>
</template>

<style lang="less" scoped>
.container {
  height: 100vh;
  background: url('@{image}/login/login-bg.jpg');
  background-size: 100% 100%;
  background-repeat: no-repeat;
  position: relative;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  padding-right: 200px;
}

.login-card {
  width: 400px;
  border-radius: 8px;
}

.card-body {

  h2 {
    text-align: center;
    font-weight: bold;
    font-family: cursive;
    color: @primary-color;
    margin-bottom: 30px;
    font-size: 30px;
  }

  .verify-box {
    height: 40px;
    cursor: pointer;

    img {
      width: 100%;
      height: 40px;
    }
  }

  .form-box {
    :deep(.ant-form) {
      .ant-input-affix-wrapper {
        height: 40px;
      }
    }
  }

  .other-mode {
    display: flex;
    justify-content: center;

    >span {
      font-size: 26px;
      width: 40px;
      height: 40px;
      color: #fff;
      border-radius: 50%;
      background-color: red;
      display: flex;
      align-items: center;
      justify-content: center;
      cursor: pointer;
      user-select: none;

      &:not(:last-child) {
        margin-right: 20px;
      }

      &:nth-child(1) {
        background-color: #10D068;
      }

      &:nth-child(2) {
        background-color: #269BEB;
      }
    }
  }

  .register-box {
    margin-top: 20px;
    text-align: center;
  }
}
</style>